<template>
  <AdVxeModal
    v-bind="$attrs"
    @register="register"
    :id="'iot-device-variable-write-modal'"
    :title="t('iot.route.device.variable.writeVariable')"
    :cancelText="t('common.cancelText')"
    :close-func="handleClose"
    :okText="t('iot.route.device.variable.writeValue')"
    @ok="handleOk"
    width="50%"
  >
    <BasicForm @register="registerForm" />
  </AdVxeModal>
</template>

<script lang="ts" setup>
  import type { PropType } from 'vue';
  import { ref } from 'vue';

  import { AdVxeModal, useModalInner } from '@/components/AdVxeModal';
  import { BasicForm, useForm, FormSchema } from '@/components/Form';

  import { useI18n } from '@/hooks/web/useI18n';
  import { isFunction } from '@/utils/is';

  import { ValueTypeEnum } from '@/enums/iot/valueTypeEnum';

  import { AjaxResult } from '#/request';
  import { DeviceVariableOutputDto } from '@/api/iot/admin/device/model';
  import { DeviceVariableInfo } from '@/api/iot/model';
  import { writeDeviceVariable } from '@/api/iot/admin/device';

  defineOptions({ name: 'DeviceVariableWriteModal' });
  const props = defineProps({
    /** 关闭回调，返回true关闭窗体 */
    closeFunc: {
      type: Function as PropType<
        (record: DeviceVariableOutputDto[], dtos: DeviceVariableInfo[]) => Promise<boolean>
      >,
      default: null,
    },
    /** 提交前回调，返回false不执行内置提交逻辑，返回true执行内置提交逻辑 */
    beforeSubmitFunc: {
      type: Function as PropType<
        (record: DeviceVariableOutputDto[], dtos: DeviceVariableInfo[]) => Promise<boolean>
      >,
      default: null,
    },
    /** 提交后回调，返回true关闭窗体 */
    afterSubmitFunc: {
      type: Function as PropType<
        (
          record: DeviceVariableOutputDto[],
          dtos: DeviceVariableInfo[],
          result?: AjaxResult | null,
        ) => Promise<boolean>
      >,
      default: null,
    },
  });

  const { t } = useI18n();

  const separator = '$#$';
  const recordRef = ref<DeviceVariableOutputDto[]>([]);

  const [registerForm, { resetFields, getFieldsValue, setProps, validate }] = useForm({
    labelWidth: 150,
    schemas: [],
    showActionButtonGroup: false,
    compact: true,
  });

  const [register, { setModalProps, closeModal, changeLoading }] = useModalInner(async (data) => {
    changeLoading(true);
    try {
      recordRef.value = data?.record || [];
      resetFields();
      if (recordRef.value.length > 0) {
        let schemas: FormSchema[] = [];
        const variableGroups = groupingBy(recordRef.value);
        for (let variableGroup in variableGroups) {
          const variables = variableGroups[variableGroup];
          // 增加分组分割线
          schemas.push({
            field: 'divider-basic',
            component: 'Divider',
            label: variableGroup,
            colProps: { span: 24 },
          });
          //设置分组变量
          variables.forEach((item) => {
            switch (item.ValueType) {
              case ValueTypeEnum.Any:
              case ValueTypeEnum.SByte:
              case ValueTypeEnum.Byte:
              case ValueTypeEnum.String:
              case ValueTypeEnum.TimeSpan:
              case ValueTypeEnum.Guid:
              case ValueTypeEnum.Bcd16:
              case ValueTypeEnum.Bcd32:
                schemas.push({
                  field: `${item.DeviceName}${separator}${item.Name}`,
                  component: 'Input',
                  label: item.Description || item.Name,
                  helpMessage: [
                    `${t('iot.route.device.nameText')}：${item.DeviceName}`,
                    `${t('iot.route.device.variable.title')}：${item.Name}`,
                    `${t('iot.route.device.variable.descriptionText')}：${
                      item.Remark || item.Description || item.Name
                    }`,
                  ],
                  // defaultValue: item.Value,
                  // defaultValueObj: item,
                  // required: true,
                  componentProps: {
                    placeholder: t('component.adtable.search.inputString'),
                    style: 'width: 100%; min-width: 100%',
                  },
                  colProps: {
                    // span: 12,
                    xs: 24, // <576px
                    sm: 24, // ≥576px
                    md: 24, // ≥768px
                    lg: 24, // ≥992px
                    xl: 12, // ≥1200px
                    xxl: 12, // ≥1600px
                    // xxxl: 12, // ≥2000px 3.0
                  },
                });
                break;
              case ValueTypeEnum.Bit:
              case ValueTypeEnum.Boolean:
                schemas.push({
                  field: `${item.DeviceName}${separator}${item.Name}`,
                  component: 'Switch',
                  label: item.Description || item.Name,
                  helpMessage: [
                    `${t('iot.route.device.nameText')}：${item.DeviceName}`,
                    `${t('iot.route.device.variable.title')}：${item.Name}`,
                    `${t('iot.route.device.variable.descriptionText')}：${
                      item.Remark || item.Description || item.Name
                    }`,
                  ],
                  defaultValue: false,
                  // defaultValueObj: item,
                  // required: true,
                  // componentProps: {
                  //   style: 'width: 100%; min-width: 100%',
                  // },
                  colProps: {
                    // span: 12,
                    xs: 24, // <576px
                    sm: 24, // ≥576px
                    md: 24, // ≥768px
                    lg: 24, // ≥992px
                    xl: 12, // ≥1200px
                    xxl: 12, // ≥1600px
                    // xxxl: 12, // ≥2000px 3.0
                  },
                });
                break;
              case ValueTypeEnum.Int16:
              case ValueTypeEnum.UInt16:
              case ValueTypeEnum.Int32:
              case ValueTypeEnum.UInt32:
              case ValueTypeEnum.Float:
              case ValueTypeEnum.Double:
                schemas.push({
                  field: `${item.DeviceName}${separator}${item.Name}`,
                  component: 'InputNumber',
                  label: item.Description || item.Name,
                  helpMessage: [
                    `${t('iot.route.device.nameText')}：${item.DeviceName}`,
                    `${t('iot.route.device.variable.title')}：${item.Name}`,
                    `${t('iot.route.device.variable.descriptionText')}：${
                      item.Remark || item.Description || item.Name
                    }`,
                  ],
                  // defaultValue: item.Value,
                  // defaultValueObj: item,
                  // required: true,
                  componentProps: {
                    placeholder: t('component.adtable.search.inputNumber'),
                    style: 'width: 100%; min-width: 100%',
                  },
                  colProps: {
                    // span: 12,
                    xs: 24, // <576px
                    sm: 24, // ≥576px
                    md: 24, // ≥768px
                    lg: 24, // ≥992px
                    xl: 12, // ≥1200px
                    xxl: 12, // ≥1600px
                    // xxxl: 12, // ≥2000px 3.0
                  },
                });
                break;
              case ValueTypeEnum.Int64:
              case ValueTypeEnum.UInt64:
              case ValueTypeEnum.Int128:
              case ValueTypeEnum.UInt128:
                schemas.push({
                  field: `${item.DeviceName}${separator}${item.Name}`,
                  component: 'Input',
                  label: item.Description || item.Name,
                  helpMessage: [
                    `${t('iot.route.device.nameText')}：${item.DeviceName}`,
                    `${t('iot.route.device.variable.title')}：${item.Name}`,
                    `${t('iot.route.device.variable.descriptionText')}：${
                      item.Remark || item.Description || item.Name
                    }`,
                  ],
                  // defaultValue: item.Value,
                  // defaultValueObj: item,
                  // required: true,
                  componentProps: {
                    placeholder: t('component.adtable.search.inputInteger'),
                    style: 'width: 100%; min-width: 100%',
                    //onKeyup: "value=value.replace(/[^{1,2,3,4,5,6,7,8,9,0}]/g,'')",
                    onKeyup: (_e: KeyboardEvent) => {
                      item.Value = item.Value.replace(/[^{1,2,3,4,5,6,7,8,9,0}]/g, '');
                    },
                  },
                  colProps: {
                    // span: 12,
                    xs: 24, // <576px
                    sm: 24, // ≥576px
                    md: 24, // ≥768px
                    lg: 24, // ≥992px
                    xl: 12, // ≥1200px
                    xxl: 12, // ≥1600px
                    // xxxl: 12, // ≥2000px 3.0
                  },
                });
                break;
              case ValueTypeEnum.DateTime:
                schemas.push({
                  field: `${item.DeviceName}${separator}${item.Name}`,
                  component: 'DatePicker',
                  label: item.Description || item.Name,
                  helpMessage: [
                    `${t('iot.route.device.nameText')}：${item.DeviceName}`,
                    `${t('iot.route.device.variable.title')}：${item.Name}`,
                    `${t('iot.route.device.variable.descriptionText')}：${
                      item.Remark || item.Description || item.Name
                    }`,
                  ],
                  // defaultValue: item.Value,
                  // defaultValueObj: item,
                  // required: true,
                  componentProps: {
                    placeholder: t('component.adtable.search.selectDateTime'),
                    style: 'width: 100%; min-width: 100%',
                    showTime: true,
                    valueFormat: 'YYYY-MM-DD HH:mm:ss',
                  },
                  colProps: {
                    // span: 12,
                    xs: 24, // <576px
                    sm: 24, // ≥576px
                    md: 24, // ≥768px
                    lg: 24, // ≥992px
                    xl: 12, // ≥1200px
                    xxl: 12, // ≥1600px
                    // xxxl: 12, // ≥2000px 3.0
                  },
                });
                break;
            }
          });
        }

        setProps({ schemas });
      }
    } finally {
      changeLoading(false);
    }
  });

  /** 变量按设备分组 */
  const groupingBy = (groupData: DeviceVariableOutputDto[]) => {
    const groupBy = (array: DeviceVariableOutputDto[], f: Function) => {
      const groups: {
        [key: string]: DeviceVariableOutputDto[];
      } = {};
      array.forEach((item) => {
        // const group = JSON.stringify(f(item));
        const group = f(item);
        groups[group] = groups[group] || [];
        groups[group].push(item);
      });
      return groups;
      // return Object.keys(groups).map((group) => {
      //   return groups[group];
      // });
    };
    const sorted = groupBy(groupData, (item: DeviceVariableOutputDto) => {
      return item.DeviceName;
    });
    return sorted;
  };

  //#region "加载状态"
  const loadingRef = ref(false);
  /** 开启加载状态 */
  function openLoading() {
    changeLoading(true);
    setModalProps({ okLoading: true, cancelLoading: true });
    loadingRef.value = true;
  }
  /** 关闭加载状态 */
  function closeLoading() {
    changeLoading(false);
    setModalProps({ okLoading: false, cancelLoading: false });
    loadingRef.value = false;
  }
  //#endregion

  /** 获取变量信息 */
  function getWriteDtos(): DeviceVariableInfo[] {
    let dtos: DeviceVariableInfo[] = [];
    const fieldValues = getFieldsValue();
    // console.log('getWriteDto', fieldValues);
    if (fieldValues) {
      for (let fieldValue in fieldValues) {
        const deviceName = fieldValue.split(separator)[0];
        const variableName = fieldValue.split(separator)[1];
        dtos.push({
          DeviceName: deviceName,
          VariableName: variableName,
          Value: fieldValues[fieldValue],
        });
      }
    }
    return dtos;
  }

  /** 处理关闭按钮 */
  async function handleClose() {
    openLoading();

    const { closeFunc } = props;
    try {
      if (closeFunc && isFunction(closeFunc)) {
        const dtos = getWriteDtos();
        const result = await closeFunc(recordRef.value, dtos);
        return result;
      }
    } finally {
      closeLoading();
    }
    return true;
  }
  /** 处理确定按钮 */
  async function handleOk() {
    const data = await validate();
    if (!data) return;
    //console.log(data);

    openLoading();
    const { beforeSubmitFunc, afterSubmitFunc } = props;
    try {
      const dtos = getWriteDtos();
      let innerSubmit = true;
      let innerCloseModal = true;
      if (beforeSubmitFunc && isFunction(beforeSubmitFunc)) {
        innerSubmit = await beforeSubmitFunc(recordRef.value, dtos);
      }
      let result: AjaxResult | null = null;
      if (innerSubmit) {
        result = await writeDeviceVariable(dtos);
      }
      if (afterSubmitFunc && isFunction(afterSubmitFunc)) {
        innerCloseModal = await afterSubmitFunc(recordRef.value, dtos, result);
      }
      if (innerCloseModal) {
        closeModal();
      }
    } finally {
      closeLoading();
    }
  }
</script>

<style lang="less" scoped></style>
